export  = {}

/** 泛型就是在使用的时才真正确定的类型*/

/* 什么是泛型
  有时候我们希望我们的这个玩意儿支持很多类型
  不管这个玩意儿是接口也好,函数也好,类也好
  你想它支持很多类型 同时这些类型之间有一些对应关系
  比如我输入什么类型 输出就是什么类型
  这个时候用any是不合适的
  所以我们就需要用一个东西表示多种类型

  用一个东西表示广泛类型
  故泛型的意思就是 我能表示广泛的类型

  我们在写ts的时候 经常需要支持多种类型 这个时候你需要一个占位符来代表多种类型
  这个占位符就是泛型(可以是任意字符 最好是一个大写T 表示Type)
*/


// function returnIt(sth: any): any {
//   return sth;
// }

// 我们期望给一个字符串就返回一个字符串 给一个数字就返回一个数字
// 但如果我们像上面这样any any,有可能给的是字符串返回的是数字,这就不是我们所期望的


/** T代表任意类型,是一个占位符(相当于变量的感觉)
 *  <T>表示【声明一个泛型变量】叫做T */
function returnSth<T/*←可以是任意字符,但默认为T,Type*/>/** ← 表示声明了一个泛型变量T, 可以有多个泛型变量*/(sth: T): T {
  return sth;
}

/** 然后调用时需要把T代表的类型显示的说出来,比如↓*/
// let s = returnIt<boolean>(true);
// let s = returnIt<boolean>(123); // TS2345: Argument of type '123' is not assignable to parameter of type 'boolean'.
// 你也可以不显示的说出来, ts会根据你传的值自动推到(尽可能的)
// let s/*←会被自动推断为 let s: string*/ = returnIt('hi');
let s = returnSth({name: 'ahhh', age: 123});

/** 泛型接口 泛型函数*/
class Person{}
interface IClazzF<T> {
  new(...args: any[]): T;
}
function getInstance<T>(Clazz: IClazzF<T>){
  return new Clazz();
}
let rr = getInstance<Person>(Person);
let rr2 = getInstance(Person);
//↑这里也可以不传<Person>, 可以自动推导
/*
  function getInstance<T>(Clazz: IClazzF<T>) --->
  IClazzF<T> ---> new(...args: any[]): T , 返回T
  也就是说Person == T ---> T 即为 Person
  So 也就可以省略了
*/


/** 类也支持泛型*/
class ClazzX<T> {

}

/** 内置的Array<T> 其实也是一种泛型的使用*/
let str: Array<string> = ['a', 'b']; // ctrl+左键点击Array 可以发现Array是一个泛型接口


/** 详情查看 07.Generics泛型/泛型与X*/


/** 泛型可以定义多个*/
function swap<T, K>(tuple: [T, K]): [K, T] {
  return [tuple[1],tuple[0]]
}
let sp = swap([1,'2'])
console.log(sp);
